#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
技术形态主引擎 - 与双轨策略同级

职责：
1. 管理所有技术形态检测器
2. 并行分析多种技术形态
3. 生成标准化交易信号
4. 提供统一的对外接口

架构：
    TechnicalEngine
        ├── pattern_detectors (形态检测器字典)
        │   ├── upper_shadow: UpperShadowPattern
        │   ├── doji: DojiPattern
        │   └── hammer: HammerPattern
        └── signal_generator (信号生成器)

使用示例：
    # 创建引擎
    engine = TechnicalEngine(config, strategy_instance)
    
    # 分析技术形态
    signals = engine.analyze_all_patterns(
        stock='000001.SZ',
        stock_data=df,
        position_info={'profit_ratio': 0.1}
    )
    
    # 获取最优信号
    if signals:
        best = signals[0]
        print(f"信号: {best['reason']}, 优先级: {best['priority']}")
"""

import pandas as pd
import numpy as np
from typing import Dict, List, Optional, Any
from datetime import datetime
import logging

from .pattern_recognition import (
    UpperShadowPattern,
    DojiPattern,
    HammerPattern
)
from .signal_generator import SignalGenerator, SignalPriority, format_signal_summary

logger = logging.getLogger(__name__)


class TechnicalEngine:
    """技术形态主引擎 - 与主策略同级"""
    
    def __init__(self, config: Dict, strategy_instance: Optional[Any] = None):
        """
        初始化技术形态引擎
        
        Args:
            config: 技术形态配置（来自 technical_patterns.yaml）
            strategy_instance: 策略实例（可选），用于获取市值等信息
        """
        self.config = config
        self.strategy = strategy_instance
        
        # 信号生成器
        self.signal_generator = SignalGenerator(config)
        
        # 统计计数器（必须在 _initialize_detectors 之前初始化）
        self.stats = {
            'total_analyzed': 0,
            'patterns_detected': 0,
            'buy_signals': 0,
            'sell_signals': 0,
            'emergency_signals': 0,
            'by_pattern': {}  # 各形态统计
        }
        
        # ⭐ 日志去重机制：与策略保持一致（由回测系统每天清空）
        # 注意：不要使用 {(stock, date): True} 字典，会造成内存泄漏且无法被回测系统清空
        self.logged_independent = set()  # 存储已输出条件D日志的股票代码（每天清空）
        self.logged_enhanced = set()  # 存储已输出技术增强日志的股票代码（每天清空）
        self.logged_strong_confirmation = set()  # 存储已输出强烈确认日志的股票代码（每天清空）
        
        # 初始化形态检测器
        self.pattern_detectors = {}
        self._initialize_detectors()
        
        logger.info(f"✅ 技术形态引擎初始化完成 - 已启用 {len(self.pattern_detectors)} 个检测器")
    
    def _initialize_detectors(self):
        """初始化各种形态检测器"""
        # 上影线检测器
        if self.config.get('upper_shadow', {}).get('enabled', False):
            self.pattern_detectors['upper_shadow'] = UpperShadowPattern(
                self.config['upper_shadow']
            )
            self.stats['by_pattern']['upper_shadow'] = {'detected': 0, 'signals': 0}
            logger.info("  ├── 上影线检测器已启用")
        
        # 十字星检测器
        if self.config.get('doji', {}).get('enabled', False):
            self.pattern_detectors['doji'] = DojiPattern(
                self.config['doji']
            )
            self.stats['by_pattern']['doji'] = {'detected': 0, 'signals': 0}
            logger.info("  ├── 十字星检测器已启用")
        
        # 锤子线检测器
        if self.config.get('hammer', {}).get('enabled', False):
            self.pattern_detectors['hammer'] = HammerPattern(
                self.config['hammer']
            )
            self.stats['by_pattern']['hammer'] = {'detected': 0, 'signals': 0}
            logger.info("  └── 锤子线检测器已启用")
    
    def evaluate_sell_signal(self,
                            stock: str,
                            strategy_signal: Optional[Dict] = None,
                            stock_data: Optional[pd.DataFrame] = None,
                            today_data: Optional[Dict] = None,
                            position_info: Optional[Dict] = None,
                            current_time: Optional[datetime] = None,
                            mode: str = 'daily',
                            metrics: Optional[Dict] = None) -> Dict:
        """
        统一评估卖出信号（简化集成接口）⭐ 新增
        
        整合独立模式（条件D）和融合模式（条件C+技术），提供一站式评估接口
        
        Args:
            stock: 股票代码
            strategy_signal: 策略信号（可选），如果为None则只检查独立触发
            stock_data: K线数据DataFrame（日线模式）
            today_data: 当日累计数据（分时模式）
            position_info: 持仓信息
            current_time: 当前时间
            mode: 分析模式 ('intraday'=分时 | 'daily'=日线)
            metrics: 预计算指标
        
        Returns:
            评估结果字典：
            {
                'action': 'independent' | 'enhanced' | 'none',  # 动作类型
                'signal': {...},  # 最终信号（已增强或独立）
                'enhancement': 0.3,  # 增强系数（仅增强模式有值）
                'tech_signals': [...],  # 原始技术信号列表
            }
        
        使用示例（策略侧）：
            # 统一评估接口，自动处理独立触发和融合增强
            tech_result = self.technical_engine.evaluate_sell_signal(
                stock=stock,
                strategy_signal=strategy_signal,  # 策略信号（可为None）
                today_data=today_data,
                position_info=position_info,
                mode='intraday',
                metrics=metrics
            )
            
            # 根据结果决定
            if tech_result['action'] == 'independent':
                # 条件D：技术独立触发
                return tech_result['signal']
            elif tech_result['action'] == 'enhanced':
                # 条件C+技术：策略信号被增强
                return tech_result['signal']
            else:
                # 无技术增强，返回原策略信号
                return strategy_signal
        """
        # 分析所有技术形态
        tech_signals = self.analyze_all_patterns(
            stock=stock,
            stock_data=stock_data,
            today_data=today_data,
            position_info=position_info,
            current_time=current_time,
            mode=mode,
            metrics=metrics
        )
        
        # 1️⃣ 检查条件D（独立触发模式）
        independent_signal = self._check_independent_mode(
            stock=stock,
            tech_signals=tech_signals,
            position_info=position_info
        )
        
        if independent_signal:
            return {
                'action': 'independent',
                'signal': independent_signal,
                'enhancement': None,
                'tech_signals': tech_signals
            }
        
        # 2️⃣ 检查融合增强模式（条件C+技术）
        if strategy_signal and tech_signals:
            enhanced_signal = self._enhance_strategy_signal(
                stock=stock,
                strategy_signal=strategy_signal,
                tech_signals=tech_signals,
                position_info=position_info
            )
            
            if enhanced_signal and 'tech_enhancement' in enhanced_signal:
                return {
                    'action': 'enhanced',
                    'signal': enhanced_signal,
                    'enhancement': enhanced_signal['tech_enhancement'],
                    'tech_signals': tech_signals
                }
        
        # 3️⃣ 无技术形态影响
        return {
            'action': 'none',
            'signal': strategy_signal,
            'enhancement': 0,
            'tech_signals': tech_signals
        }
    
    def _check_independent_mode(self,
                               stock: str,
                               tech_signals: List[Dict],
                               position_info: Optional[Dict] = None) -> Optional[Dict]:
        """
        检查技术形态是否满足独立触发条件（条件D）
        
        Args:
            stock: 股票代码
            tech_signals: 技术信号列表（已排序）
            position_info: 持仓信息
        
        Returns:
            独立触发信号，如果不满足条件则返回None
        """
        # 检查是否启用独立模式
        independent_config = self.config.get('upper_shadow', {}).get('independent_mode', {})
        if not independent_config.get('enabled', False):
            return None
        
        # 检查是否有卖出信号
        if not tech_signals:
            return None
        
        # 获取最强卖出信号
        best_signal = None
        for signal in tech_signals:
            if signal.get('signal_type') == 'sell':
                best_signal = signal
                break  # 已按优先级排序，第一个就是最优
        
        if not best_signal:
            return None
        
        # 检查强度是否达到独立触发阈值
        min_strength = independent_config.get('min_strength', 2.5)
        strength = best_signal.get('strength', 0)
        
        if strength < min_strength:
            logger.debug(f"[{stock}] 技术形态强度{strength:.2f}<{min_strength:.2f}，未达到独立触发阈值")
            return None
        
        # 构建独立触发信号
        stock_type = self._get_stock_type(stock)
        stock_type_map = {'large': '大盘股', 'medium': '中盘股', 'small': '小盘股'}
        stock_type_name = stock_type_map.get(stock_type, stock_type)
        
        # 获取形态名称
        pattern_name_map = {'upper_shadow': '上影线', 'doji': '十字星', 'hammer': '锤子线'}
        pattern_display = pattern_name_map.get(best_signal.get('pattern'), best_signal.get('pattern'))
        
        # 构建详细原因（包含指标对比）⭐ 从配置文件读取阈值
        details = best_signal.get('details', {})
        pattern = best_signal.get('pattern')
        config_key = best_signal.get('config_key')  # 'large_cap', 'medium_cap', 'small_cap'
        reason_parts = [f"【条件D】技术形态独立触发({stock_type_name}): {pattern_display}形态"]
        
        # 添加指标对比（从配置文件读取阈值）
        indicator_parts = []
        indicator_parts.append(f"强度{strength:.2f}≥阈值{min_strength:.2f}")
        
        # 根据形态类型从配置读取阈值
        if pattern == 'upper_shadow' and pattern in self.config:
            # 获取形态配置
            sell_signals = self.config[pattern].get('sell_signals', {})
            
            # config_key可能为None，需要兜底处理
            if not config_key:
                # 根据stock_type推断config_key
                config_key_map = {'large': 'large_cap', 'medium': 'medium_cap', 'small': 'small_cap'}
                config_key = config_key_map.get(stock_type, 'large_cap')
                logger.debug(f"[{stock}] config_key为空，根据stock_type推断为: {config_key}")
            
            pattern_config = sell_signals.get(config_key, {})
            
            # 如果还是空，打印调试信息
            if not pattern_config:
                logger.warning(f"[{stock}] 无法从配置获取 {pattern}.sell_signals.{config_key}，使用默认值")
            
            # 上影线比例对比
            if 'upper_shadow_ratio' in details:
                upper_ratio = details['upper_shadow_ratio']
                threshold = pattern_config.get('shadow_ratio', 0)
                indicator_parts.append(f"上影线{upper_ratio:.1%}≥阈值{threshold:.1%}")
            
            # 量比对比
            if 'volume_ratio' in details:
                vol_ratio = details['volume_ratio']
                threshold = pattern_config.get('volume_min', 0)
                indicator_parts.append(f"量比{vol_ratio:.2f}≥阈值{threshold:.2f}")
            
            # 价格位置对比
            if 'price_position' in details:
                price_pos = details['price_position']
                threshold = pattern_config.get('position_min', 0)
                indicator_parts.append(f"价格位置{price_pos:.1%}≥阈值{threshold:.1%}")
        else:
            # 其他形态或配置缺失时的回退逻辑
            if 'upper_shadow_ratio' in details:
                indicator_parts.append(f"上影线{details['upper_shadow_ratio']:.1%}")
            if 'volume_ratio' in details:
                indicator_parts.append(f"量比{details['volume_ratio']:.2f}")
            if 'price_position' in details:
                indicator_parts.append(f"价格位置{details['price_position']:.1%}")
        
        reason = f"{reason_parts[0]} + {' + '.join(indicator_parts)}"
        
        independent_signal = {
            'type': 'sell',
            'condition_type': 'tech_independent',  # 条件D
            'reason': reason,
            'sell_ratio': 1.0,  # 独立触发默认全仓卖出
            'source': 'technical_independent',
            'pattern': best_signal.get('pattern'),
            'tech_strength': strength,
            'priority': best_signal.get('priority', 9),
            'details': details,
            'timestamp': datetime.now()
        }
        
        # ⭐ 日志去重：每个股票每天只输出一次（由回测系统每天清空set）
        if stock not in self.logged_independent:
            logger.warning(f"⚡ [{stock}] 条件D触发：技术形态独立信号（强度{strength:.2f}≥{min_strength:.2f}）")
            self.logged_independent.add(stock)
        else:
            # 今天已经输出过，改为DEBUG级别
            logger.debug(f"[{stock}] 条件D持续触发：强度{strength:.2f}")
        
        return independent_signal
    
    def _enhance_strategy_signal(self,
                                stock: str,
                                strategy_signal: Dict,
                                tech_signals: List[Dict],
                                position_info: Optional[Dict] = None) -> Optional[Dict]:
        """
        使用技术形态增强策略信号（融合模式）
        
        Args:
            stock: 股票代码
            strategy_signal: 原始策略信号
            tech_signals: 技术信号列表
            position_info: 持仓信息
        
        Returns:
            增强后的信号，如果无需增强则返回None
        """
        # 获取增强配置
        enhancement_config = self.config.get('signal_enhancement', {})
        if not enhancement_config:
            return None
        
        rules = enhancement_config.get('enhancement_rules', {})
        min_strength = rules.get('min_strength', 2.0)
        strong_strength = rules.get('strong_strength', 3.0)
        enhancement_factor = rules.get('enhancement_factor', 0.3)
        scale = rules.get('strength_to_enhancement_scale', 10.0)
        
        # 获取最强卖出信号
        best_tech = None
        for signal in tech_signals:
            if signal.get('signal_type') == 'sell':
                best_tech = signal
                break
        
        if not best_tech:
            return None
        
        tech_strength = best_tech.get('strength', 0)
        
        # 检查强度是否达到增强阈值
        if tech_strength < min_strength:
            logger.debug(f"[{stock}] 技术形态强度{tech_strength:.2f}<{min_strength:.2f}，不增强")
            return None
        
        # 计算增强系数
        if tech_strength >= strong_strength:
            # 强烈确认：使用线性缩放
            enhancement_range = rules.get('enhancement_range', [0.0, 0.3, 0.5])
            max_enhancement = enhancement_range[2] if len(enhancement_range) > 2 else 0.5
            enhancement = min(max_enhancement, tech_strength / scale)
        else:
            # 一般确认：使用固定因子
            enhancement_range = rules.get('enhancement_range', [0.0, 0.3, 0.5])
            enhancement = enhancement_range[1] if len(enhancement_range) > 1 else enhancement_factor
        
        # 复制并增强信号
        enhanced_signal = strategy_signal.copy()
        enhanced_signal['condition_type'] = 'tech_enhanced'  # 条件C+技术
        enhanced_signal['tech_enhancement'] = enhancement
        enhanced_signal['tech_strength'] = tech_strength
        enhanced_signal['pattern'] = best_tech.get('pattern')
        
        # 更新原因
        pattern_name_map = {'upper_shadow': '上影线', 'doji': '十字星', 'hammer': '锤子线'}
        pattern_name = pattern_name_map.get(best_tech.get('pattern', ''), best_tech.get('pattern', ''))
        tech_info = f"{pattern_name}确认(强度{tech_strength:.1f})"
        
        # 在原因中添加技术形态信息
        original_reason = enhanced_signal.get('reason', '')
        if '|' in original_reason:
            # 已有分隔符，直接添加
            enhanced_signal['reason'] = f"{original_reason} | {tech_info}"
        else:
            # 无分隔符，添加分隔符
            enhanced_signal['reason'] = f"{original_reason} | {tech_info}"
        
        # 检查是否需要调整卖出比例
        ratio_config = enhancement_config.get('sell_ratio_adjustment', {})
        if ratio_config.get('enable_ratio_boost', False):
            strong_threshold = ratio_config.get('strong_enhancement_threshold', 0.3)
            if enhancement >= strong_threshold:
                # 技术形态强烈确认，改为全部清仓
                enhanced_signal['sell_ratio'] = 1.0
                enhanced_signal['reason'] += " | 技术形态强烈确认，全部清仓"
                
                # ⭐ 强烈确认日志（去重：每个股票每天只输出一次）
                if stock not in self.logged_strong_confirmation:
                    logger.info(f"📊 [{stock}] 技术形态强烈确认(增强≥{strong_threshold:.0%})，改为全部清仓")
                    self.logged_strong_confirmation.add(stock)
                else:
                    # 今天已经输出过，改为DEBUG级别
                    logger.debug(f"[{stock}] 技术形态持续强烈确认(增强{enhancement:.1%}，全部清仓)")
        
        # ⭐ 日志去重：融合日志（每个股票每天只输出一次，由回测系统每天清空set）
        if stock not in self.logged_enhanced:
            logger.info(f"📊 [{stock}] 技术形态融合: {tech_info} | 增强系数{enhancement:.1%}")
            self.logged_enhanced.add(stock)
        else:
            # 今天已经输出过，改为DEBUG级别
            logger.debug(f"[{stock}] 技术形态持续增强: {tech_info} | 增强{enhancement:.1%}")
        
        return enhanced_signal
    
    def analyze_all_patterns(self,
                            stock: str,
                            stock_data: Optional[pd.DataFrame] = None,
                            today_data: Optional[Dict] = None,
                            position_info: Optional[Dict] = None,
                            current_time: Optional[datetime] = None,
                            mode: str = 'daily',
                            metrics: Optional[Dict] = None) -> List[Dict]:
        """
        并行分析所有技术形态（主要入口）
        
        Args:
            stock: 股票代码
            stock_data: K线数据DataFrame（日线模式使用）
            today_data: 当日累计数据（分时模式使用），格式：
                {
                    'open': 当日开盘价,
                    'high': 当日最高价（截止当前）,
                    'low': 当日最低价（截止当前）,
                    'last': 当前价格,
                    'volume': 当日累计成交量
                }
            position_info: 持仓信息（可选），格式：
                {
                    'buy_price': 买入价格,
                    'current_price': 当前价格,
                    'profit_ratio': 盈利比例（0.1表示10%）
                }
            current_time: 当前时间
            mode: 分析模式 ('intraday'=分时回测 | 'daily'=日线回测)
            metrics: 预计算的公共指标（共享策略数据，避免重复计算），格式：
                {
                    'volume_ratio': 量比（当前量/5日均量）,
                    'price_position': 价格位置（0-1，相对60日高低点）,
                    'avg_volume': 平均成交量,
                    'ma5': 5日均线,
                    'ma10': 10日均线,
                    'ma20': 20日均线
                }
        
        Returns:
            信号列表，按优先级排序（优先级高的在前）
        """
        self.stats['total_analyzed'] += 1
        
        # ⭐ 数据验证
        if mode == 'intraday':
            # 分时模式：验证today_data
            if not today_data or 'high' not in today_data or 'low' not in today_data:
                logger.debug(f"[{stock}] 技术形态分析: 分时数据为空，跳过")
                return []
        else:
            # 日线模式：验证stock_data
            if stock_data is None or len(stock_data) == 0:
                logger.debug(f"[{stock}] 技术形态分析: 日线数据为空，跳过")
                return []
        
        signals = []
        
        # 获取股票类型（大中小盘）
        stock_type = self._get_stock_type(stock)
        
        # 遍历所有启用的检测器
        for pattern_name, detector in self.pattern_detectors.items():
            try:
                # ⭐ 根据模式调用不同的分析方法
                if mode == 'intraday':
                    # 分时模式：使用today_data（共享策略计算的数据）
                    pattern_result = detector.analyze(
                        today_data=today_data,  # ⭐ 传递today_data
                        stock_type=stock_type, 
                        position_info=position_info,
                        mode='intraday',
                        metrics=metrics  # ⭐ 传递预计算指标
                    )
                else:
                    # 日线模式：使用stock_data（DataFrame）
                    pattern_result = detector.analyze(
                        df=stock_data,  # 传递DataFrame
                        stock_type=stock_type, 
                        position_info=position_info,
                        mode='daily',
                        metrics=metrics  # ⭐ 传递预计算指标
                    )
                
                detected_time = None  # 记录检测到信号的时间
                
                if pattern_result:
                    detected_time = 'current'
                    logger.debug(f"[{stock}] 检测到 {pattern_name}")
                
                # 2️⃣ 如果当前没检测到信号（暂时移除回溯逻辑，后续优化）
                elif False:  # 暂时禁用回溯
                    logger.debug(f"[{stock}] 当前K线未检测到{pattern_name}，开始回溯检测...")
                    
                    # 从最近的K线开始往前回溯
                    for i in range(1, lookback_minutes + 1):
                        # 构建截止到历史时刻的数据
                        historical_data = stock_data.iloc[:-i]
                        
                        if len(historical_data) < 10:  # 数据不足，停止回溯
                            break
                        
                        # 检测这个历史时刻的最后一根K线
                        historical_result = detector.analyze(
                            historical_data,
                            stock_type,
                            position_info
                        )
                        
                        if historical_result:
                            # 找到历史信号
                            pattern_result = historical_result
                            detected_time = f'lookback-{i}min'
                            
                            # 标记为回溯检测
                            pattern_result['lookback'] = True
                            pattern_result['lookback_minutes'] = i
                            
                            logger.info(f"[{stock}] 🔍 回溯检测到 {pattern_name}（{i}分钟前）")
                            break  # 找到信号后停止回溯
                
                # 3️⃣ 如果检测到信号（当前或回溯），生成交易信号
                if pattern_result:
                    # 更新统计
                    self.stats['patterns_detected'] += 1
                    self.stats['by_pattern'][pattern_name]['detected'] += 1
                    
                    # 生成信号
                    signal = self.signal_generator.generate_signal(
                        pattern_result, 
                        position_info
                    )
                    
                    if signal:
                        # 添加股票信息
                        signal['stock'] = stock
                        
                        # 标记检测方式
                        if detected_time and detected_time != 'current':
                            signal['detected_by'] = detected_time
                        
                        signals.append(signal)
                        
                        # 更新统计
                        self.stats['by_pattern'][pattern_name]['signals'] += 1
                        
                        signal_type = signal.get('signal_type', 'unknown')
                        if signal_type == 'buy':
                            self.stats['buy_signals'] += 1
                        elif signal_type == 'sell':
                            self.stats['sell_signals'] += 1
                            
                            if signal.get('urgency') == 'emergency':
                                self.stats['emergency_signals'] += 1
                        
                        # 记录日志（融合模式：仅记录debug级别，减少输出）
                        # 注意：融合模式下，技术形态不再独立决策，日志降级为debug
                        self._log_signal(stock, signal, position_info, log_level='debug')
            
            except Exception as e:
                logger.error(f"[{stock}] {pattern_name}形态分析异常: {e}", exc_info=True)
        
        # 按优先级排序（优先级高的在前）
        signals = self._prioritize_signals(signals)
        
        # 输出分析结果摘要（融合模式：降级为debug，减少输出）
        if signals:
            logger.debug(f"[{stock}] 技术形态分析: 检测到{len(signals)}个信号: {', '.join([s.get('pattern', '未知') for s in signals])}")
        # 未检测到信号时不输出
        
        return signals
    
    def _get_stock_type(self, stock: str) -> str:
        """
        获取股票类型（大中小盘）
        
        Returns:
            'large', 'medium', 'small', 或 'unknown'
        """
        try:
            if self.strategy and hasattr(self.strategy, 'get_stock_type'):
                return self.strategy.get_stock_type(stock)
            else:
                # 没有策略实例，使用默认值
                return 'medium'
        except Exception as e:
            logger.warning(f"获取{stock}股票类型失败: {e}，使用默认中盘股")
            return 'medium'
    
    def _prioritize_signals(self, signals: List[Dict]) -> List[Dict]:
        """
        信号优先级排序
        
        排序规则：
        1. 优先级高的在前
        2. 同优先级，强度大的在前
        3. 同强度，时间新的在前
        """
        if not signals:
            return []
        
        sorted_signals = sorted(
            signals,
            key=lambda x: (
                -x.get('priority', 0),           # 优先级降序
                -x.get('strength', 0),           # 强度降序
                -x.get('timestamp', datetime.min).timestamp()  # 时间降序
            )
        )
        
        return sorted_signals
    
    def _log_signal(self, stock: str, signal: Dict, position_info: Optional[Dict], log_level: str = 'info'):
        """
        记录信号日志
        
        Args:
            stock: 股票代码
            signal: 信号字典
            position_info: 持仓信息
            log_level: 日志级别（'debug'=融合模式，减少输出；'info'/'warning'=独立模式）
        """
        # 融合模式：默认使用debug级别，减少日志输出
        if log_level == 'debug':
            log_func = logger.debug
        else:
            signal_type = signal.get('signal_type', 'unknown')
            urgency = signal.get('urgency', 'normal')
            
            # 根据紧急程度选择日志级别
            if urgency == 'emergency':
                log_func = logger.warning
            elif urgency == 'high':
                log_func = logger.warning
            else:
                log_func = logger.info
        
        # 构建日志消息
        log_msg = f"[{stock}] {format_signal_summary(signal)}"
        
        if position_info:
            profit_ratio = position_info.get('profit_ratio', 0)
            log_msg += f"\n  当前盈亏: {profit_ratio:.2%}"
        
        log_func(log_msg)
    
    def check_buy_risk(self, stock: str, signals: List[Dict]) -> Dict:
        """
        检查买入风险（基于技术信号）
        
        如果存在强烈的卖出警告，则阻止买入
        
        Args:
            stock: 股票代码
            signals: 技术信号列表
        
        Returns:
            {
                'allowed': 是否允许买入,
                'reason': 原因
            }
        """
        if not signals:
            return {'allowed': True, 'reason': ''}
        
        # 检查是否有强烈的卖出警告
        sell_signals = [s for s in signals if s.get('signal_type') == 'sell']
        strong_sells = [s for s in sell_signals if s.get('strength', 0) >= 3.0]
        
        if strong_sells:
            strongest = max(strong_sells, key=lambda x: x.get('strength', 0))
            return {
                'allowed': False,
                'reason': f"技术形态卖出警告: {strongest.get('reason', '未知原因')}"
            }
        
        return {'allowed': True, 'reason': ''}
    
    def get_best_signal(self, signals: List[Dict]) -> Optional[Dict]:
        """
        获取最优信号（优先级最高的）
        
        Args:
            signals: 信号列表
        
        Returns:
            最优信号，如果列表为空返回 None
        """
        if not signals:
            return None
        return signals[0]  # 已按优先级排序
    
    def filter_by_type(self, signals: List[Dict], signal_type: str) -> List[Dict]:
        """
        按类型过滤信号
        
        Args:
            signals: 信号列表
            signal_type: 'buy', 'sell', 或 'neutral'
        
        Returns:
            过滤后的信号列表
        """
        return [s for s in signals if s.get('signal_type') == signal_type]
    
    def get_statistics(self) -> Dict:
        """获取统计信息"""
        stats = self.stats.copy()
        
        # 添加信号生成器统计
        stats['signal_generator'] = self.signal_generator.get_statistics()
        
        return stats
    
    def reset_statistics(self):
        """重置统计信息"""
        self.stats = {
            'total_analyzed': 0,
            'patterns_detected': 0,
            'buy_signals': 0,
            'sell_signals': 0,
            'emergency_signals': 0,
            'by_pattern': {name: {'detected': 0, 'signals': 0} 
                          for name in self.pattern_detectors.keys()}
        }
        self.signal_generator.reset_statistics()
    
    def print_statistics(self):
        """打印统计报告"""
        stats = self.get_statistics()
        
        print("\n" + "="*60)
        print("技术形态引擎统计报告")
        print("="*60)
        print(f"总分析次数: {stats['total_analyzed']}")
        print(f"检测到形态: {stats['patterns_detected']}")
        print(f"生成买入信号: {stats['buy_signals']}")
        print(f"生成卖出信号: {stats['sell_signals']}")
        print(f"紧急信号数: {stats['emergency_signals']}")
        
        print("\n各形态统计:")
        for pattern_name, pattern_stats in stats['by_pattern'].items():
            print(f"  {pattern_name}:")
            print(f"    检测到: {pattern_stats['detected']}")
            print(f"    生成信号: {pattern_stats['signals']}")
        
        print("="*60 + "\n")



if __name__ == '__main__':
    """测试代码"""
    import yaml
    
    # 加载测试配置
    try:
        with open('../config/technical_patterns.yaml', 'r', encoding='utf-8') as f:
            config = yaml.safe_load(f)
    except:
        print("配置文件加载失败，使用默认配置")
        config = {
            'upper_shadow': {
                'enabled': True,
                'min_kline_range': 0.5,
                'sell_signals': {
                    'medium_cap': {
                        'shadow_ratio': 0.65,
                        'volume_min': 1.4,
                        'position_min': 0.75,
                        'scoring': {
                            'shadow': {
                                'excellent': [0.80, 2.0],
                                'good': [0.70, 1.5],
                                'normal': [0.65, 1.0]
                            },
                            'volume': {
                                'excellent': [2.2, 1.0],
                                'good': [1.6, 0.5]
                            },
                            'position': {
                                'excellent': [0.90, 1.0],
                                'good': [0.80, 0.5]
                            },
                            'profit': {
                                'excellent': [0.15, 1.0],
                                'good': [0.10, 0.5]
                            },
                            'trend': {
                                'strong_uptrend': 0.5
                            }
                        }
                    }
                },
                'buy_signals': {'enabled': False},
                'strength_threshold': {
                    'sell_suggest': 2.5,
                    'sell_confirm': 3.0,
                    'sell_emergency': 3.5
                },
                'market_environment': {
                    'strong_uptrend': {'ma_spacing_min': 4.0},
                    'price_position': {'lookback_days': 60}
                }
            },
            'doji': {'enabled': False},
            'hammer': {'enabled': False}
        }
    
    # 创建引擎
    engine = TechnicalEngine(config)
    
    # 创建测试数据
    test_data = pd.DataFrame({
        'open': [100, 102, 105, 108, 110],
        'high': [103, 110, 112, 115, 120],
        'low': [99, 101, 104, 107, 109],
        'close': [102, 105, 106, 109, 111],
        'volume': [1000000, 1500000, 2000000, 2500000, 3000000],
        'MA5': [100, 101, 102, 103, 104],
        'MA10': [99, 100, 101, 102, 103],
        'MA20': [98, 99, 100, 101, 102]
    })
    
    # 测试分析
    signals = engine.analyze_all_patterns(
        stock='000001.SZ',
        stock_data=test_data,
        position_info={'profit_ratio': 0.12}
    )
    
    print(f"\n检测到 {len(signals)} 个信号")
    
    for i, signal in enumerate(signals, 1):
        print(f"\n信号 {i}:")
        print(f"  形态: {signal['pattern']}")
        print(f"  类型: {signal['signal_type']}")
        print(f"  原因: {signal['reason']}")
        print(f"  强度: {signal['strength']}")
        print(f"  优先级: {signal['priority']} ({SignalPriority.get_priority_name(signal['priority'])})")
        print(f"  动作: {signal['action']}")
    
    # 打印统计
    engine.print_statistics()

